<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <title>Guarding against CSRFs</title>
    <base href="http://bhs.googlecode.com/svn/trunk/"><!--[if IE]></base><![endif]-->
</head>
<body bgcolor="white">
<h1>Guarding against Cross Site Request Forgeries</h1>
<p>If your application uses cookies or sessions (cookies indeirectly) for user authentication, it is trusting the
browser to be authenticated, not truly the user. Other code running in the browser, such as a malicious application,
is able to use the browser, complete with cookies, to impersonate the user and appear to your application as the
user. Roughly speaking, this is the basis for CSRFs. You can read more on CSRF attacks in any treatment of
AJAX security.</p>
<h2>BHF CSRF Tokens</h2>
<p>The BHF provides native token support to guard against CSRF attacks, but you still must be aware how it works
to know where your application is protected and where it is open. The CSRF Token (realized in the <code>CSRFTOken</code>
class) is an encrypted, date stamped token, that allows access to the methods of a specific service. The token is
contained in your pages, rather than in a cookie, so that you are reasonably assured that the request comes from
one of your pages, rather than a malicious site. The assumpion is that you are otherwise protected the page content
through the use of SSL and authentication of the user. You must never include a token for a sensitive service in
a page that could be publicly viewed. This constraint may effect how you break up service methods across service:
not mixing sensitive and public methods in the same service.</p>
<p>Tokens are specific to a 24 hour period and a given service. This limits the first order damage of a compromised
token to a given service on a given day.</p>

<h2>Pages</h2>
Any URL that can be hit directly from the browser (initial log-in, redirect targets, bookmarks, ...) cannot be directly
protected against CSRF because that are, effectively, initiated cross site. In addition, the tokens would expire and
be unusable at a later date to reach the page. For these reasons, Pages are not protected from CSRF attacks and should
be 'safe' on their own. If a Page displays sensitive information, it should fetch that information using a call to a
protected service after the page has loaded. Access a Page should not have any side effects. Note also that cached
pages may have expired tokens and will need to be reloaded if the tokens are older than 24 hours.

<h2>Allowing Cross Site Access to Service</h2>
<p>To allow cross site access to a Service, you must, obviously, turn off cross site protection. When you do so,
be aware that you cannot trust the code making requests to your services. The <code>ServiceMethod</code> annotation
has a boolean parameter <code>crossSite</code> that you can set to <code>true</code> to allow cross site access to
that method. Recall that cross site access is implicitly granted to all Page service methods.</p>
<h2>How to Use CSRF Tokens</h2>
<p>If you use the BHF tags to generate JavaScript stubs to access services, the BHF will take of the CSRF tokens
for you. If you use the BHF JS library directly, you will need to call <code>setToken(...)</code> on your service
objects (components, widgets, ... as well) to set the access token. To generate a token you can use the BHF
    <code>token</code> JSP tag or the <code>CSRFToken</code> class.
</p>
<p>Because CSRF Tokens depend on encryption, you must bind an <code>EncryptionFacility</code> during application
initialization.</p>
<code><pre>
    ...
    Facilities.bind( ConfigurationFacility.class, FileConfiguration.class );
    ...
    Facilities.bind( EncryptionFacility.class, PBEEncryptionFacility.class );
    ...
</pre></code>
<p>The CSRF token must be URI encoded and added as the <code>t</code> of any request to a CSRF protected method.</p>
<h2>Complex Example</h2>
<p>The following javaScript shows a CSRF token being used to access a list of application users to feed a YUI
table widget.</p>
<code><pre>
    YAHOO.util.Event.onDOMReady(function(){
    var $=function(x){return document.getElementById(x);}
    var messageHandler = BHF.MessageStuffer();
    var <strong>token</strong> = '&lt;bhf:token service='com.candogo.admin.user.UsersDataSource' /&gt;';

    ...

    //
    // CRUD
    //
    var crud = &lt;bhf:service service="com.candogo.admin.packages.PackageCRUD" /&gt;;

    ...

    //
    // Data Source
    //

    var data = new YAHOO.util.DataSource( BHF.fixRelativeURL( '/service/users/' ) );
        data.responseType = YAHOO.util.DataSource.TYPE_JSON;
        data.connXhrMode = "cancelStaleRequests";
        data.responseSchema =
        {
            resultsList: "items",
            fields: [ 'id', 'firstName', 'lastName', 'email', 'disabled', 'lastLogin' ]
        };

    //
    // Table
    //

    ...

    var table = new YAHOO.widget.DataTable(
            'users',
            [
                {key: 'lastName',     label: 'Last Name',       sortable: true, width: '10em' },
                {key: 'firstName',    label: 'First Name',      sortable: true, width: '10em' },
                {key: 'email',        label: 'eMail',           sortable: true, width: '14em', formatter: YAHOO.widget.DataTable.formatEmail },
                {key: 'lastLogin',    label: 'Last Login',      sortable: false, width: '10em', formatter: dateRenderer },
                {key: 'disabled',     label: 'Disabled',        sortable: false, width: '5em' },
                {                     label: 'Actions',         formatter: removeButtonRenderer }
            ],
            data,
            {
                initialRequest:
                    'first?' +
                    't=' + encodeURIComponent( <strong>token</strong> ) +
                    '&a=' + encodeURIComponent( YAHOO.lang.JSON.stringify( {start: 0, count: 15, sortColumn: 'lastName', sortAscending: true} ) )
            }
        );

    //
    // Pager and specialization to handle search
    //

    var pager = new BHF.table.Pager( 'pager', table, data, { pageSize: 15, sortColumn: 'lastName', token: <strong>token</strong> } );

    ...
});
</pre></code>
</body>
</html>